﻿namespace VIT.BusinessLogicLayer
{
    using System;
    using System.Linq;
    using System.Collections.Generic;

    using VIT.DataAccessLayer;
    using VIT.DataTransferObjects.Presentation;
    using VIT.Entity;
    using VIT.Library;
    using VIT.Library.Web;

    /// <summary>
    /// Category logic
    /// </summary>
    public class ItemBLL : BLLBase
    {
        #region Properties
        private readonly IItemDAL _itemDAL;
        private readonly IItemViewDAL _itemViewDAL;
        private readonly IItemCommentDAL _itemCommentDAL;
        private readonly IItemImageDAL _itemImageDAL;
        private readonly IItemLikeDAL _itemLikeDAL;
        private readonly IItemVoteDAL _itemVoteDAL;
        private readonly IBanIPDAL _banIpDAL;
        private readonly IColorDAL _colorDAL;

        private readonly string _domainStore;
        private readonly string _imageItemDetailPath;
        private readonly string _imageItemThumbPath;

        private readonly URL _url;
        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ItemBLL"/> class. 
        /// </summary>
        /// <param name="connectionString">
        /// The connection string.
        /// </param>
        public ItemBLL(string connectionString = "")
            : base(connectionString)
        {
            this._itemDAL = new ItemDAL(this.DatabaseFactory);
            this._itemViewDAL = new ItemViewDAL(this.DatabaseFactory);
            this._itemCommentDAL = new ItemCommentDAL(this.DatabaseFactory);
            this._itemImageDAL = new ItemImageDAL(this.DatabaseFactory);
            this._itemLikeDAL = new ItemLikeDAL(this.DatabaseFactory);
            this._itemVoteDAL = new ItemVoteDAL(this.DatabaseFactory);
            this._banIpDAL = new BanIPDAL(this.DatabaseFactory);

            this._domainStore = SettingsManager.AppSettings.DomainStore;
            this._imageItemDetailPath = SettingsManager.Constants.LinkItemDetailImage;
            this._imageItemThumbPath = SettingsManager.Constants.LinkItemThumbImage;

            this._url = new URL();
        }
        #endregion

        #region Item
        /// <summary>
        ///  Change Publish List Item
        /// </summary>
        /// <param name="ids">
        /// The ids.
        /// </param>
        /// <param name="publish">
        /// The publish.
        /// </param>
        /// <param name="userModify">
        /// The user modify.
        /// </param>
        /// <returns>
        /// Publish success
        /// </returns>
        public bool ChangePublishList(string[] ids, bool publish, string userModify)
        {
            try
            {
                foreach (var id in ids)
                {
                    int i;
                    if (!int.TryParse(id, out i))
                    {
                        i = 0;
                    }

                    var item = this._itemDAL.Get(o => o.Id == i);
                    if (item == null)
                    {
                        continue;
                    }

                    item.IsPublished = publish;
                    item.ModifyDate = DateTime.Now;
                    item.ModifyByUser = userModify;
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Change Publish Item
        /// </summary>
        /// <param name="id">
        /// The ids.
        /// </param>
        /// <param name="publish">
        /// The publish.
        /// </param>
        /// <param name="userModify">
        /// The user modify.
        /// </param>
        /// <returns>
        /// Publish success
        /// </returns>
        public bool ChangePublish(int id, bool publish, string userModify)
        {
            try
            {
                var item = this._itemDAL.Get(o => o.Id == id);
                if (item != null)
                {
                    item.IsPublished = publish;
                    item.ModifyDate = DateTime.Now;
                    item.ModifyByUser = userModify;
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Change Order Item
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <param name="order">
        /// The order.
        /// </param>
        /// <param name="userModify">
        /// The user modify.
        /// </param>
        /// <returns>
        /// Change success
        /// </returns>
        public bool ChangeOrder(int id, Order order, string userModify)
        {
            try
            {
                var item = this._itemDAL.Get(o => o.Id == id);
                if (item != null)
                {
                    switch (order)
                    {
                        case Order.Up:
                            item.Orders++;
                            break;
                        case Order.Down:
                            item.Orders--;
                            break;
                    }

                    item.ModifyDate = DateTime.Now;
                    item.ModifyByUser = userModify;
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Change Delete List Item
        /// </summary>
        /// <param name="ids">
        /// The ids.
        /// </param>
        /// <param name="delete">
        /// The delete.
        /// </param>
        /// <param name="userModify">
        /// The user modify.
        /// </param>
        /// <returns>
        /// Is Success
        /// </returns>
        public bool ChangeDeleteStatusList(List<int> ids, bool delete, string userModify)
        {
            try
            {
                foreach (var id in ids)
                {
                    var item = this._itemDAL.Get(o => o.Id == id);
                    if (item == null)
                    {
                        continue;
                    }

                    item.HasDeleted = delete;
                    item.DeleteDate = DateTime.Now;
                    item.DeleteByUser = userModify;
                    this._itemDAL.Update(item);
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Change Delete Item
        /// </summary>
        /// <param name="id">
        /// The ids.
        /// </param>
        /// <param name="delete">
        /// The delete.
        /// </param>
        /// <param name="userModify">
        /// The user modify.
        /// </param>
        /// <returns>
        /// Is Success
        /// </returns>
        public bool ChangeDeleteStatus(int id, bool delete, string userModify)
        {
            try
            {
                var item = this._itemDAL.Get(o => o.Id == id);
                if (item != null)
                {
                    item.HasDeleted = delete;
                    item.DeleteByUser = userModify;
                    item.DeleteDate = DateTime.Now;
                    this._itemDAL.Update(item);
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Deletes Item
        /// </summary>
        /// <param name="ids">
        /// The ids.
        /// </param>>
        /// <returns>
        /// Delete success
        /// </returns>
        public bool Deletes(List<int> ids)
        {
            try
            {
                foreach (var id in ids)
                {
                    var grp = this._itemDAL.Get(o => o.Id == id);
                    if (grp != null)
                    {
                        this._itemDAL.Delete(grp);
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region ItemView
        /// <summary>
        /// Get Like
        /// </summary>
        /// <param name="id">mã item</param>
        /// <returns>Like number</returns>
        public LikeDto GetLike(int id)
        {
            var query = this._itemLikeDAL.GetAll()
                .Where(o => o.ItemId == id)
                .Select(o => new LikeDto
                {
                    Id = o.ItemId,
                    Like = o.Likes,
                    Unlike = o.UnLikes
                });

            var item = query.FirstOrDefault();

            if (item == null) return new LikeDto();
            return item;
        }

        /// <summary>
        /// Đánh giá
        /// </summary>
        /// <param name="id">mã item cần vote</param>
        /// <param name="rate">giá trị</param>
        /// <param name="voteDefault">vote mặc định nếu VoteNumber = 0</param>
        /// <returns>
        /// giá trị tỉ lệ VoteRate/VoteNumber
        /// -1: nếu không tồn tại id
        /// </returns>
        public int UpdateVoteRate(int id, int rate, int voteDefault)
        {
            var item = this._itemVoteDAL.Get(e => e.ItemId == id);
            if (item == null)
            {
                item = new ItemVote();
                item.ItemId = id;
                item.VoteNumber = 1;
                item.VoteRate = rate;

                this._itemVoteDAL.Add(item);
            }
            else
            {
                item.VoteNumber += 1;
                item.VoteRate += rate;

                this._itemVoteDAL.Update(item);
            }

            try
            {
                this.SaveChanges();

                if (item.VoteNumber > 0)
                    return item.VoteRate / item.VoteNumber;
                return voteDefault;
            }
            catch (Exception ex)
            {
                throw new BusinessLogicLayerException(ex.Message);
            }

            return -1;
        }

        /// <summary>
        /// Tăng số view
        /// </summary>
        /// <param name="id">mã item</param>
        public void UpdateView(int id)
        {
            var item = this._itemViewDAL.GetById(id);
            if (item == null)
            {
                item = new ItemView();
                item.ItemId = id;
                item.Views = 1;
                this._itemViewDAL.Add(item); 
            }
            else
            {
                item.Views += 1;
                this._itemViewDAL.Update(item); 
            }

            try
            {
                this.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new BusinessLogicLayerException(ex.Message);
            }
        }

        /// <summary>
        /// Tăng số like
        /// </summary>
        /// <param name="id">mã item</param>
        public void UpdateLike(int id)
        {
            var view = this._itemLikeDAL.GetById(id);
            if (view == null)
            {
                view = new ItemLike();
                view.ItemId = id;
                this._itemLikeDAL.Add(view);
            }
            else
            {
                this._itemLikeDAL.Update(view);
            }

            try
            {
                view.Likes += 1;
                this.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new BusinessLogicLayerException(ex.Message);
            }
        }

        /// <summary>
        /// Tăng số unlike
        /// </summary>
        /// <param name="id">mã item</param>
        public void UpdateUnlike(int id)
        {
            var view = this._itemLikeDAL.GetById(id);
            if (view == null)
            {
                view = new ItemLike();
                view.ItemId = id;
                this._itemLikeDAL.Add(view);
            }
            else
            {
                this._itemLikeDAL.Update(view);
            }

            try
            {
                view.UnLikes += 1;
                this.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new BusinessLogicLayerException(ex.Message);
            }
        }
        #endregion

        #region ItemComment
        public CommentDto GetCommentById(int Id)
        {
            var query = _itemCommentDAL.GetAllIncludeItemView()
                .Where(ItemComment => ItemComment.Id == Id && ItemComment.Item.IsPublished)
                .Select(c => new CommentDto
                {
                    ClientId = c.ClientId,
                    Description = c.Description,
                    Id = c.Id,
                    Name = c.Item.CreateByUser,
                    Time = c.Item.CreateDate,
                    Likes = c.Item.ItemLike == null ? 0 : c.Item.ItemLike.Likes,
                    UnLikes = c.Item.ItemLike == null ? 0 : c.Item.ItemLike.UnLikes
                });

            var comment = query.FirstOrDefault();

            return comment;
        }

        public IList<CommentDto> GetCommentByItem(int itemId)
        {
            var comments = _itemCommentDAL.GetAllIncludeItemView()
                .Where(comment => comment.ItemId == itemId && comment.Item.IsPublished)
                .OrderByDescending(c => c.Item.CreateDate)
                .Select(c => new CommentDto
                {
                    ClientId = c.ClientId,
                    Description = c.Description,
                    Id = c.Id,
                    Name = c.Item.CreateByUser,
                    Time = c.Item.CreateDate,
                    Likes = c.Item.ItemLike == null ? 0 : c.Item.ItemLike.Likes,
                    UnLikes = c.Item.ItemLike == null ? 0 : c.Item.ItemLike.UnLikes
                });
            return comments.ToList();
        }

        public void InsertComment(int companyId, int itemId, string name, string description, string localIP, bool isPublish)
        {
            var banIp = this._banIpDAL.Get(e => e.IP == localIP && e.CompanyId == companyId);
            if (banIp != null) throw new BusinessLogicLayerException(banIp.Note);

            var comment = new ItemComment();
            comment.Item = new Item();
            comment.Item.CompanyId = companyId;
            comment.Item.CreateDate = DateTime.Now;
            comment.Item.CreateByUser = name;
            comment.Item.IsPublished = isPublish;
            comment.ItemId = itemId;
            comment.Description = description;
            comment.ClientId = localIP;

            try
            {
                this._itemCommentDAL.Add(comment);
                this.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new BusinessLogicLayerException("Không thể lưu vì: " + ex.Message);
            }
        }
        #endregion

        #region ItemImage
        public List<ItemImageDto> GetImageForProduct(int productId, int companyId)
        {
            var list = this._itemImageDAL.GetMany(o => o.ItemId == productId && o.Item.CompanyId == companyId)
                .Select(image => new ItemImageDto
                    {
                        Id = image.Id,
                        Description = image.Description,
                        ImageName = image.ImageName,
                        ItemId = productId
                    });

            var data = list.ToList();

            var imageItemThumbPath = string.Format(this._imageItemThumbPath, companyId);
            var imageItemDetailPath = string.Format(this._imageItemDetailPath, companyId);
            foreach (var productImageDto in data)
            {
                productImageDto.ImageThumbPath = this._url.VirtualPath(imageItemThumbPath + productImageDto.ImageName);
                productImageDto.ImageDetailPath = this._url.VirtualPath(imageItemDetailPath + productImageDto.ImageName);
            }

            return data;
        }

        public List<ItemImageDto> GetImageForProduct(int productId, int companyId, int skip, int take)
        {
            var list = this._itemImageDAL.GetMany(o => o.ItemId == productId && o.Item.CompanyId == companyId)
                 .Select(image => new ItemImageDto
                    {
                        Id = image.Id,
                        Description = image.Description,
                        ImageName = image.ImageName,
                        ItemId = productId
                    });

            if (skip > 0) list = list.Skip(skip);
            if (take > 0) list = list.Take(take);
            
            var data = list.ToList();

            var imageItemThumbPath = string.Format(this._imageItemThumbPath, companyId);
            var imageItemDetailPath = string.Format(this._imageItemDetailPath, companyId);
            foreach (var productImageDto in data)
            {
                productImageDto.ImageThumbPath = this._url.VirtualPath(imageItemThumbPath + productImageDto.ImageName);
                productImageDto.ImageDetailPath = this._url.VirtualPath(imageItemDetailPath + productImageDto.ImageName);
            }

            return data;
        }        
        #endregion
    }
}
